package com.xueyi.workflow.controller;

import com.xueyi.common.core.web.page.TableDataInfo;
import com.xueyi.common.core.web.result.AjaxResult;
import com.xueyi.common.core.web.validate.V_A;
import com.xueyi.common.log.annotation.Log;
import com.xueyi.common.log.enums.BusinessType;
import com.xueyi.common.security.annotation.AdminAuth;
import com.xueyi.common.security.auth.pool.WorkflowPool;
import com.xueyi.common.web.entity.controller.BasisController;
import com.xueyi.workflow.domain.dto.WfProcessApprovalDto;
import com.xueyi.workflow.domain.dto.WfProcessInstanceDto;
import com.xueyi.workflow.domain.dto.WfProcessTaskDto;
import com.xueyi.workflow.domain.dto.WfProcessVersionDto;
import com.xueyi.workflow.domain.query.WfProcessApprovalQuery;
import com.xueyi.workflow.domain.query.WfProcessInstanceQuery;
import com.xueyi.workflow.domain.query.WfProcessTaskQuery;
import com.xueyi.workflow.domain.vo.WfWorkbenchVo;
import com.xueyi.workflow.service.IWfProcessApprovalService;
import com.xueyi.workflow.service.IWfProcessInstanceService;
import com.xueyi.workflow.service.IWfProcessService;
import com.xueyi.workflow.service.IWfProcessTaskService;
import com.xueyi.workflow.service.IWfProcessVersionService;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import com.xueyi.workflow.domain.dto.StartProcessRequest;
import com.xueyi.workflow.domain.dto.GetNextNodesRequest;
import com.xueyi.workflow.domain.vo.NextNodeInfo;
import com.xueyi.workflow.domain.dto.SubmitApprovalRequest;
import com.xueyi.workflow.domain.dto.PersonnelQueryRequest;
import com.xueyi.workflow.domain.vo.PersonnelInfo;

/**
 * 工作流管理Controller
 *
 * @author xueyi
 * @date 2024-07-03
 */
@Slf4j
@AdminAuth
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/processFlow")
public class WfProcessController extends BasisController {

    private final IWfProcessService wfProcessService;
    private final IWfProcessInstanceService wfProcessInstanceService;
    private final IWfProcessTaskService wfProcessTaskService;
    private final IWfProcessApprovalService wfProcessApprovalService;
    private final IWfProcessVersionService wfProcessVersionService;

    /**
     * 获取授权流程列表
     */
    @GetMapping("/authorizedProcessList")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_PROCESS_START_LIST + "')")
    public AjaxResult getAuthorizedProcessList() {
        List<Map<String, Object>> list = wfProcessService.getAuthorizedProcessList();
        return success(list);
    }

    /**
     * 获取流程表单绑定信息
     */
    @GetMapping("/processFormBind/{processId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_PROCESS_START_DETAIL + "')")
    public AjaxResult getProcessFormBind(@PathVariable @NotNull String processId) {
        Map<String, Object> bindInfo = wfProcessService.getProcessFormBind(processId);
        return success(bindInfo);
    }

    /**
     * 获取流程版本信息
     */
    @GetMapping("/processVersion/{processId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_PROCESS_START_DETAIL + "')")
    public AjaxResult getProcessVersion(@PathVariable @NotNull String processId,
                                       @RequestParam(required = false) Integer version) {
        WfProcessVersionDto versionInfo = wfProcessVersionService.getProcessVersion(processId, version);
        return success(versionInfo);
    }

    /**
     * 通过流程版本ID获取流程版本信息
     */
    @GetMapping("/processVersionById/{versionId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_PROCESS_START_DETAIL + "')")
    public AjaxResult getProcessVersionById(@PathVariable @NotNull Long versionId) {
        WfProcessVersionDto versionInfo = wfProcessVersionService.getProcessVersionById(versionId);
        return success(versionInfo);
    }

    /**
     * 获取流程版本信息（通过processKey）
     */
    @GetMapping("/processVersionByKey/{processKey}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_PROCESS_START_DETAIL + "')")
    public AjaxResult getProcessVersionByKey(@PathVariable @NotNull String processKey,
                                            @RequestParam(required = false) Integer version) {
        WfProcessVersionDto versionInfo = wfProcessVersionService.getProcessVersionByKey(processKey, version);
        return success(versionInfo);
    }

    /**
     * 发起流程
     */
    @PostMapping("/startProcess")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_PROCESS_START_CREATE + "')")
    @Log(title = "工作流管理", businessType = BusinessType.INSERT)
    public AjaxResult startProcess(@Validated @RequestBody StartProcessRequest request) {
        try {
            WfProcessInstanceDto instance = wfProcessInstanceService.startProcess(request);
            return success(instance);
        } catch (Exception e) {
            return error("流程发起失败: " + e.getMessage());
        }
    }

    /**
     * 查询流程实例列表
     */
    @GetMapping("/processInstanceList")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_MY_PROCESS_LIST + "')")
    public AjaxResult getProcessInstanceList(WfProcessInstanceQuery query) {
        TableDataInfo<WfProcessInstanceDto> list = wfProcessInstanceService.queryPageList(query);
        return success(list);
    }

    /**
     * 获取流程实例详情
     */
    @GetMapping("/processInstanceDetail/{id}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_MY_PROCESS_DETAIL + "')")
    public AjaxResult getProcessInstanceDetail(@PathVariable @NotNull Long id) {
        WfProcessInstanceDto detail = wfProcessInstanceService.getProcessInstanceDetail(id);
        return success(detail);
    }

    /**
     * 撤销流程实例
     */
    @PostMapping("/cancelProcessInstance/{id}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_MY_PROCESS_CANCEL + "')")
    @Log(title = "工作流管理", businessType = BusinessType.DELETE)
    public AjaxResult cancelProcessInstance(@PathVariable @NotNull String id,
                                           @RequestBody(required = false) Map<String, String> requestBody) {
        String reason = requestBody != null ? requestBody.get("reason") : "用户撤销";
        Boolean result = wfProcessInstanceService.cancelProcessInstance(id, reason);
        return toAjax(result);
    }

    /**
     * 挂起流程实例
     */
    @PostMapping("/suspendProcessInstance/{id}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_MY_PROCESS_CANCEL + "')")
    @Log(title = "工作流管理", businessType = BusinessType.UPDATE)
    public AjaxResult suspendProcessInstance(@PathVariable @NotNull String id) {
        Boolean result = wfProcessInstanceService.suspendProcessInstance(id);
        return toAjax(result);
    }

    /**
     * 恢复流程实例
     */
    @PostMapping("/resumeProcessInstance/{id}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_MY_PROCESS_CANCEL + "')")
    @Log(title = "工作流管理", businessType = BusinessType.UPDATE)
    public AjaxResult resumeProcessInstance(@PathVariable @NotNull String id) {
        Boolean result = wfProcessInstanceService.resumeProcessInstance(id);
        return toAjax(result);
    }

    /**
     * 获取我的待办任务
     */
    @GetMapping("/myTasks")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_LIST + "')")
    public AjaxResult getMyTasks(WfProcessTaskQuery query) {
        TableDataInfo<WfProcessTaskDto> list = wfProcessTaskService.getMyTasks(query);
        return success(list);
    }

    /**
     * 获取任务详情
     */
    @GetMapping("/taskDetail/{taskId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_DETAIL + "')")
    public AjaxResult getTaskDetail(@PathVariable @NotNull String taskId) {
        WfProcessTaskDto detail = wfProcessTaskService.getTaskDetail(taskId);
        return success(detail);
    }

    /**
     * 认领任务
     */
    @PostMapping("/claimTask/{taskId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_PROCESS + "')")
    @Log(title = "工作流管理", businessType = BusinessType.UPDATE)
    public AjaxResult claimTask(@PathVariable @NotNull String taskId) {
        Boolean result = wfProcessTaskService.claimTask(taskId);
        return toAjax(result);
    }

    /**
     * 取消认领任务
     */
    @PostMapping("/unclaimTask/{taskId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_PROCESS + "')")
    @Log(title = "工作流管理", businessType = BusinessType.UPDATE)
    public AjaxResult unclaimTask(@PathVariable @NotNull String taskId) {
        Boolean result = wfProcessTaskService.unclaimTask(taskId);
        return toAjax(result);
    }

    /**
     * 委派任务
     */
    @PostMapping("/delegateTask/{taskId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_PROCESS + "')")
    @Log(title = "工作流管理", businessType = BusinessType.UPDATE)
    public AjaxResult delegateTask(@PathVariable @NotNull String taskId,
                                  @RequestParam @NotEmpty String assignee) {
        Boolean result = wfProcessTaskService.delegateTask(taskId, assignee);
        return toAjax(result);
    }

    /**
     * 转办任务
     */
    @PostMapping("/transferTask/{taskId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_PROCESS + "')")
    @Log(title = "工作流管理", businessType = BusinessType.UPDATE)
    public AjaxResult transferTask(@PathVariable @NotNull String taskId,
                                  @RequestParam @NotEmpty String assignee) {
        Boolean result = wfProcessTaskService.transferTask(taskId, assignee);
        return toAjax(result);
    }

    /**
     * 获取审批历史
     */
    @GetMapping("/approvalHistory/{processInstanceId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_MY_PROCESS_DETAIL + "')")
    public AjaxResult getApprovalHistory(@PathVariable @NotNull String processInstanceId) {
        log.info("获取审批历史，流程实例ID: {}", processInstanceId);
        
        try {
            List<WfProcessApprovalDto> history = wfProcessApprovalService.getApprovalHistory(processInstanceId);
            log.info("获取审批历史成功，记录数量: {}", history.size());
            return success(history);
        } catch (Exception e) {
            log.error("获取审批历史失败，流程实例ID: {}", processInstanceId, e);
            return error("获取审批历史失败: " + e.getMessage());
        }
    }

    /**
     * 获取下一步节点数据
     */
    @PostMapping("/getNextNodes")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_PROCESS + "')")
    public AjaxResult getNextNodes(@RequestBody GetNextNodesRequest request) {
        log.info("获取下一步节点数据，请求模式: {}, 任务ID: {}, 流程实例ID: {}, 流程ID: {}, 流程Key: {}", 
                request.isStartMode() ? "发起模式" : "任务处理模式",
                request.getTaskId(), request.getProcessInstanceId(), request.getProcessId(), request.getProcessKey());
        
        try {
            // 手动验证请求参数
            if (request.isStartMode()) {
                if (request.getProcessId() == null && request.getProcessKey() == null) {
                    return error("发起模式需要提供processId或processKey");
                }
            } else if (request.isTaskMode()) {
                if (request.getTaskId() == null) {
                    return error("任务处理模式需要提供taskId");
                }
                if (request.getProcessInstanceId() == null) {
                    return error("任务处理模式需要提供processInstanceId");
                }
            } else {
                return error("请求参数不完整，发起模式需要提供processId或processKey，任务处理模式需要提供taskId和processInstanceId");
            }
            
            List<NextNodeInfo> nextNodes;
            
            if (request.isStartMode()) {
                // 发起模式：根据流程ID或Key获取下一节点
                nextNodes = wfProcessTaskService.getNextNodesForStart(
                    request.getProcessId(), 
                    request.getProcessKey(), 
                    request.getFormData()
                );
            } else if (request.isTaskMode()) {
                // 任务处理模式：根据任务ID获取下一节点
                nextNodes = wfProcessTaskService.getNextNodes(
                    request.getTaskId(), 
                    request.getProcessInstanceId(), 
                    request.getFormData()
                );
            } else {
                return error("请求参数不完整，发起模式需要提供processId或processKey，任务处理模式需要提供taskId和processInstanceId");
            }
            
            return success(nextNodes);
        } catch (Exception e) {
            log.error("获取下一步节点数据失败", e);
            return error("获取下一步节点数据失败: " + e.getMessage());
        }
    }

    /**
     * 获取节点状态
     */
    @GetMapping("/nodeStatus/{processInstanceId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_MY_PROCESS_DETAIL + "')")
    public AjaxResult getNodeStatus(@PathVariable String processInstanceId) {
        try {
            // 从Flowable获取流程实例的节点状态
            List<WfProcessTaskDto> nodeStatusList = wfProcessTaskService.getNodeStatus(processInstanceId);
            return success(nodeStatusList);
        } catch (Exception e) {
            log.error("获取节点状态失败，processInstanceId: {}", processInstanceId, e);
            return error("获取节点状态失败: " + e.getMessage());
        }
    }

    /**
     * 获取当前任务节点配置
     */
    @GetMapping("/currentTaskNodeConfig/{taskId}")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_PROCESS + "')")
    public AjaxResult getCurrentTaskNodeConfig(@PathVariable String taskId) {
        log.info("获取当前任务节点配置，任务ID: {}", taskId);
        
        try {
            NextNodeInfo currentNodeConfig = wfProcessTaskService.getCurrentTaskNodeConfig(taskId);
            if (currentNodeConfig != null) {
                return success(currentNodeConfig);
            } else {
                return error("未找到任务节点配置");
            }
        } catch (Exception e) {
            log.error("获取当前任务节点配置失败，taskId: {}", taskId, e);
            return error("获取当前任务节点配置失败: " + e.getMessage());
        }
    }

    /**
     * 添加审批记录
     */
    @PostMapping("/addApprovalRecord")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_PROCESS + "')")
    @Log(title = "工作流管理", businessType = BusinessType.INSERT)
    public AjaxResult addApprovalRecord(@Validated(V_A.class) @RequestBody WfProcessApprovalQuery query) {
        log.info("添加审批记录，流程实例ID: {}", query.getProcessInstanceId());
        
        try {
            boolean result = wfProcessApprovalService.addApprovalRecord(query);
            if (result) {
                return success("审批记录添加成功");
            } else {
                return error("审批记录添加失败");
            }
        } catch (Exception e) {
            log.error("添加审批记录失败", e);
            return error("添加审批记录失败: " + e.getMessage());
        }
    }

    /**
     * 提交审核
     */
    @PostMapping("/submitApproval")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_PROCESS + "')")
    @Log(title = "工作流管理", businessType = BusinessType.UPDATE)
    public AjaxResult submitApproval(@Validated @RequestBody SubmitApprovalRequest request) {
        log.info("提交审核，任务ID: {}, 流程实例ID: {}, 审批结果: {}", 
                request.getTaskId(), request.getProcessInstanceId(), request.getApprovalResult());
        
        try {
            Boolean result = wfProcessTaskService.submitApproval(request);
            if (result) {
                return success("审核提交成功");
            } else {
                return error("审核提交失败");
            }
        } catch (Exception e) {
            log.error("提交审核失败", e);
            return error("提交审核失败: " + e.getMessage());
        }
    }

    /**
     * 获取工作台数据
     */
    @GetMapping("/workbenchData")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_WORKBENCH_LIST + "')")
    public AjaxResult getWorkbenchData() {
        try {
            WfWorkbenchVo data = wfProcessService.getWorkbenchData();
            return success(data);
        } catch (Exception e) {
            log.error("获取工作台数据失败", e);
            return error("获取工作台数据失败: " + e.getMessage());
        }
    }

    /**
     * 获取工作台任务
     */
    @GetMapping("/workbenchTasks")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_TODO_LIST + "')")
    public AjaxResult getWorkbenchTasks(@RequestParam(defaultValue = "5") Integer limit) {
        try {
            List<WfProcessTaskDto> tasks = wfProcessTaskService.getWorkbenchTasks(limit);
            return success(tasks);
        } catch (Exception e) {
            log.error("获取工作台任务失败", e);
            return error("获取工作台任务失败: " + e.getMessage());
        }
    }

    /**
     * 查询流程历史列表
     */
    @GetMapping("/processHistoryList")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_HISTORY_LIST + "')")
    public AjaxResult getProcessHistoryList(WfProcessInstanceQuery query) {
        TableDataInfo<WfProcessInstanceDto> list = wfProcessInstanceService.getProcessHistoryList(query);
        return success(list);
    }

    /**
     * 查询任务历史列表
     */
    @GetMapping("/taskHistoryList")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_HISTORY_LIST + "')")
    public AjaxResult getTaskHistoryList(WfProcessTaskQuery query) {
        TableDataInfo<WfProcessTaskDto> list = wfProcessTaskService.getTaskHistoryList(query);
        return success(list);
    }

    /**
     * 导出历史数据
     */
    @PostMapping("/exportHistoryData")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_HISTORY_EXPORT + "')")
    @Log(title = "工作流管理", businessType = BusinessType.EXPORT)
    public void exportHistoryData(@RequestParam String type,
                                 @RequestParam(required = false) String startDate,
                                 @RequestParam(required = false) String endDate,
                                 HttpServletResponse response) {
        wfProcessService.exportHistoryData(type, startDate, endDate, response);
    }

    /**
     * 获取节点名称
     */
    @GetMapping("/nodeName")
    public String getNodeName() {
        return "工作流管理";
    }

    /**
     * 根据角色、部门、岗位ID获取人员列表
     */
    @PostMapping("/getPersonnelList")
    @PreAuthorize("@ss.hasAuthority('" + WorkflowPool.WORKFLOW_PROCESS_START_DETAIL + "')")
    public AjaxResult getPersonnelList(@RequestBody @Validated PersonnelQueryRequest request) {
        try {
            List<PersonnelInfo> personnelList = wfProcessService.getPersonnelList(request);
            return success(personnelList);
        } catch (Exception e) {
            log.error("获取人员列表失败", e);
            return error("获取人员列表失败: " + e.getMessage());
        }
    }
}
